package com.inspinia.base.util;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * 单机排队自旋任务锁(CLH锁)
 *
 * 参考博客
 * https://coderbee.net/index.php/concurrent/20131115/577  (CLH锁部分)
 */
public class JobCLHLock {
    public static class JobCLHNode {
        private volatile boolean isLocked = true; // 默认是在等待锁
    }

    private static JobCLHLock clhLock;

    static {
        if (clhLock == null){
            clhLock = new JobCLHLock();
        }
    }

    /**
     * 默认指向最后一个节点
     */
    private volatile JobCLHNode tail ;
    private static final AtomicReferenceFieldUpdater<JobCLHLock, JobCLHNode> UPDATER = AtomicReferenceFieldUpdater
                  . newUpdater(JobCLHLock.class, JobCLHNode .class , "tail" );

    public static void lock(JobCLHNode currentThread) {
        //取出当前存放的节点,将新的节点放入
        //取出的节点则为当前节点的前一节点
        JobCLHNode preNode = UPDATER.getAndSet( clhLock, currentThread);
        if(preNode != null) {//已有线程占用了锁，进入自旋
            //使用前一节点的属性判断是否应该自旋等待锁释放
            while(preNode.isLocked ) {
            }
        }
    }

    public static void unlock(JobCLHNode currentThread) {
        // 如果队列里只有当前线程，则释放对当前线程的引用（for GC）。
        if (!UPDATER .compareAndSet(clhLock, currentThread, null)) {
            // 还有后续线程
            currentThread. isLocked = false ;// 改变状态，让后续线程结束自旋
        }
    }
}